package bancosys.tec.services.implementor.annotations.visitor;

import java.lang.annotation.Annotation;
import java.lang.reflect.Member;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;

import jmine.tec.di.annotation.visitor.InjectedAnnotationVisitor;
import jmine.tec.di.cache.TypeMatchLookup;
import jmine.tec.di.metadata.DependencyMetaData;
import jmine.tec.di.metadata.impl.DependencyMetaDataImpl;
import jmine.tec.di.resolver.ObjectResolver;
import jmine.tec.di.resolver.impl.DynamicObjectResolver;
import jmine.tec.di.type.NoTypeConverter;
import jmine.tec.di.type.TypeConverter;
import jmine.tec.di.wrapper.Wrapper;
import jmine.tec.di.wrapper.Wrappers;
import jmine.tec.services.annotations.Parameter;

import org.hibernate.SessionFactory;

import bancosys.tec.services.implementor.descriptor.CachedObjectResolver;

/**
 * AnnotationVisitor para {@link Parameter}
 * 
 * @author takeshi
 */
public class ParameterAnnotationVisitor extends SetterAndParametersAnnotationVisitor<DependencyMetaData> {
    private final TypeMatchLookup<TypeConverter<?>> typeConvertion;

    private final TypeMatchLookup<ObjectResolver> objectResolvers;

    /**
     * @param typeConvertion o conversor de tipos
     * @param objectResolvers os static resolvers
     */
    public ParameterAnnotationVisitor(TypeMatchLookup<TypeConverter<?>> typeConvertion, TypeMatchLookup<ObjectResolver> objectResolvers) {
        super(Parameter.class);
        this.typeConvertion = typeConvertion;
        this.objectResolvers = objectResolvers;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Collection<? extends DependencyMetaData> onParameterAnnotation(Annotation annotation, Class<?> annotated, int parameterIndex,
            Class<?> parameterType, Type genericType, Member annotatedMember) {
        Parameter parameter = (Parameter) annotation;
        Wrapper wrapper = Wrappers.findWrapperFor(parameterType);
        String propertyName = parameter.value();
        Class<?> componentType = InjectedAnnotationVisitor.resolveGenericType(genericType, annotated);
        ObjectResolver resolver =
                new DynamicObjectResolver(componentType, propertyName, this.typeConvertion.lookup(componentType, NoTypeConverter
                        .getInstance()), null);
        if (parameter.cached()) {
            final long timeout = 10000L;
            resolver = new CachedObjectResolver(resolver, this.objectResolvers.lookup(SessionFactory.class, null), timeout, propertyName);
        }
        return Collections.singleton(new DependencyMetaDataImpl(propertyName, resolver, true, wrapper, componentType));
    }

}
